' DOSDoors - Video Setup Routines
#Print Video.bas

#include once "main.bi"
#include once "video.bi"
#include once "vars.bi"
#include once "interp.bi"

' Implemented:
' -------------------------
' Timers:               No          0
' Buttons:              Yes         1
' Checkbox:             Yes         2
' Radio Button:         No          3
' Vertical Scrollbar:   No          4
' Horizontal Scrollbar: Yes         5
' Left/Right Slider:    No          6
' Menu:                 No          7
' Dropdown Listbox:     No          8

TotalWindows = -1

' Moves windowNum to the top of the Z-Order
Sub SetZOrderTop(windowNum As Integer)
    #ifdef DEBUG_LOG
        LogString("SetZOrderTop")
    #endif

    Dim As Integer totalItems, moveItem

    totalItems = TotalWindows
    Do Until totalItems = 1
        If Window_ZOrder(totalItems) = windowNum Then moveItem = 1
        If moveItem = 1 Then Window_ZOrder(totalItems) = Window_ZOrder(totalItems - 1)
        totalItems = totalItems - 1
    Loop

    Window_ZOrder(1) = windowNum
    SetVariable("System.OS.Display.Windows.Active", Str(windowNum))
    SetVariable("System.OS.Display.Windows.Active.Name", Window_Caption(windowNum))
    
    #ifdef DEBUG_LOG
        LogString("SetZOrderTop::End")
    #endif
End Sub

' Test to see if mouse is inside a door
Function TestInsideDoor(mouseX As Integer, mouseY As Integer) As Integer
    #ifdef DEBUG_LOG
        LogString("TestInsideDoor")
    #endif

    Dim As Integer tempLoop, X1, Y1, X2, Y2
      
    Do Until (tempLoop >= TotalWindows)
        tempLoop = tempLoop + 1
        X1 = Window_X1(Window_ZOrder(tempLoop))
        Y1 = Window_Y1(Window_ZOrder(tempLoop))
        X2 = Window_X2(Window_ZOrder(tempLoop))
        Y2 = Window_Y2(Window_ZOrder(tempLoop))
        If Window_Visible(tempLoop) = 1 Then
            If (mouseX > X1) And (mouseX < X2) Then
                If (mouseY > Y1) And (mouseY < Y2) Then
                    Return Window_ZOrder(tempLoop)
                    Exit Do
                End If
            End If
        End If
    Loop

    #ifdef DEBUG_LOG
        LogString("TestInsideDoor:End")
    #endif

    Return 0
End Function

' Test to see if a control was clicked (following Z-Order
Function TestControlClicked(mouseX As Integer, mouseY As Integer) As Integer
    #ifdef DEBUG_LOG
        LogString("TestControlClicked")
    #endif

    Dim As Integer tempLoop, X1, Y1
    Dim As Integer tempLoop2, X1a, Y1a, Widtha, Heighta
    
    Do Until (tempLoop >= TotalWindows)
        tempLoop = tempLoop + 1

        X1 = Window_X1(Window_ZOrder(tempLoop)) + 1
        Y1 = Window_Y1(Window_ZOrder(tempLoop)) + 12                
        'X2 = Window_X2(Window_ZOrder(tempLoop))
        'Y2 = Window_Y2(Window_ZOrder(tempLoop))

        tempLoop2 = 0
        Do Until (tempLoop2 >= TotalControls)
            tempLoop2 = tempLoop2 + 1
            If Window_Controls(tempLoop2).Parent = Window_ZOrder(tempLoop) Then
                If Window_Visible(Window_ZOrder(tempLoop)) = 1 Then
                    If Window_Controls(tempLoop2).Enabled = 1 Then
                        X1a = Window_Controls(tempLoop2).X + X1
                        Y1a = Window_Controls(tempLoop2).Y + Y1
                        Widtha = Window_Controls(tempLoop2).Width + X1a
                        Heighta = Window_Controls(tempLoop2).Height + Y1a
                    
                        ' Correct for windows without captions
                        If Window_CaptionVisible(Window_ZOrder(tempLoop)) <> 1 Then
                            Y1a = Y1a - 11
                            Heighta = Heighta - 11
                        End If

                        ' Line (X1a, Y1a) - (Widtha, Heighta), 0, bf
                        If (mouseX > X1a) And (mouseX < Widtha) Then
                            If (mouseY > Y1a) And (mouseY < Heighta) Then
                                Return tempLoop2
                                Exit Do
                            End If
                        End If
                    End If
                End If
            End If
        Loop
    Loop

    #ifdef DEBUG_LOG
        LogString("TestControlClicked:End")
    #endif

    Return 0
End Function

' Test to see if mouse is inside a door caption
Function TestDragging(mouseX As Integer, mouseY As Integer) As Integer
    #ifdef DEBUG_LOG
        LogString("TestDragging")
    #endif

    Dim As Integer tempLoop, X1, Y1, X2, Y2
    Dim As UByte HasCaption

    Do Until (tempLoop >= TotalWindows)
        tempLoop = tempLoop + 1
        X1 = Window_X1(tempLoop)
        Y1 = Window_Y1(tempLoop)
        X2 = Window_X2(tempLoop)
        Y2 = Window_Y2(tempLoop)
        HasCaption = Window_CaptionVisible(tempLoop)
        ' Make sure there's a captionbar to click in
        If (mouseX > X1) And (mouseX < X2) Then
            'If (mouseY > Y1) And (mouseY < Y2) Then
            If (mouseY > Y1) And (mouseY < Y1 + 12) Then
                If HasCaption = 1 Then
                    DraggingWindow = 1
                    Dragging_Num = tempLoop
                    Dragging_StartX = mouseX - X1
                    Dragging_StartY = mouseY - Y1
                    Return tempLoop
                End If
                Exit Do
            End If
        End If
    Loop

    #ifdef DEBUG_LOG
        LogString("TestDragging:End")
    #endif

    Return 0
End Function

' Blit a door to the screen
Function BlitDoor(WindowNum As Integer) As Integer
    #ifdef DEBUG_LOG
        LogString("BlitDoor")
    #endif

    Dim doorDC As Any Ptr
    doorDC = GetWindowBuffer(Window_Name(WindowNum))

    Put (Window_X1(WindowNum), Window_Y1(WindowNum)), doorDC, PSet

    #ifdef DEBUG_LOG
        LogString("BlitDoor:End")
    #endif

    Return 0
End Function

' Redraws the controls for a door
Sub RedrawControls(WindowNum As Integer)
    #ifdef DEBUG_LOG
        LogString("RedrawControls")
    #endif

    Dim As Integer tempLoop, X1, Y1, X2, Y2
    Dim As String Text
    Dim As UByte HasCaption

    Do Until (tempLoop >= TotalControls)
        tempLoop = tempLoop + 1
        If Window_Controls(tempLoop).Parent = WindowNum Then
            If Window_Controls(tempLoop).Visible = 1 Then
                X1 = Window_Controls(tempLoop).X + 1
                Y1 = Window_Controls(tempLoop).Y + 12
                X2 = Window_Controls(tempLoop).X + Window_Controls(tempLoop).Width + 1
                Y2 = Window_Controls(tempLoop).Y + Window_Controls(tempLoop).Height + 12
                Text = Left(Window_Controls(tempLoop).Text, Window_Controls(tempLoop).Text_Length)
                HasCaption = Window_CaptionVisible(WindowNum)                

                ' No caption, so undo the Height change
                If HasCaption = 0 Then
                    Y1 = Y1 - 11
                    Y2 = Y2 - 11
                End If

                Select Case Window_Controls(tempLoop).Type
                    Case 1  ' Command Button
                        DrawButton (Window_Image(WindowNum), X1, Y1, X2, Y2, Text, Window_Controls(tempLoop).Value, Window_Controls(tempLoop).Enabled)
                    Case 2  ' Checkbox
                        DrawCheckbox (Window_Image(WindowNum), X1, Y1, X2, Y2, Text, Window_Controls(tempLoop).Value, Window_Controls(tempLoop).Enabled)
                End Select
            End If
        End If
    Loop

    #ifdef DEBUG_LOG
        LogString("RedrawControls:End")
    #endif
End Sub

' Set's a Door's property
Function SetDoorProperty(WindowNum As Integer, PropertyName As String, PropertyValue As String) As Integer
    Dim As Integer tempLoop, X1, Y1, X2, Y2
    Dim As String tempName

    #ifdef DEBUG_LOG
        LogString("SetDoorProperty")
    #endif

    Select Case LCase(PropertyName)
        Case "visible"
            If (LCase(PropertyValue) = "0") OR (Lcase(PropertyValue) = "false") Then
                Window_Visible(WindowNum) = 0
            Else
                Window_Visible(WindowNum) = 1
            End If

            ' Redraw the doors so the visuals take effect
            UpdateScreen = 1
    End Select

    #ifdef DEBUG_LOG
        LogString("SetDoorProperty:End")
    #endif

    Return 0
End Function

' Set's a control's property
Function SetControlProperty(WindowNum As Integer, ControlName As String, PropertyName As String, PropertyValue As String) As Integer
    Dim As Integer tempLoop, X1, Y1, X2, Y2
    Dim As String tempName

    #ifdef DEBUG_LOG
        LogString("SetControlProperty")
    #endif

    Do Until (tempLoop >= TotalControls)
        tempLoop = tempLoop + 1

        If Window_Controls(tempLoop).Parent = WindowNum Then
            tempName = Left(Window_Controls(tempLoop).Name, Window_Controls(tempLoop).Name_Length)
            If LCase(tempName) = LCase(ControlName) Then
                ' Do a test for timers
                If Window_Controls(tempLoop).Type = 0 Then
                    SetTimerProperty(Window_Controls(tempLoop).ProgramOwner, tempName, PropertyName, PropertyValue)
                    Exit Do
                End If

                ' Not a timer
                Select Case LCase(PropertyName)
                    Case "x"
                        Window_Controls(tempLoop).X = ValInt(PropertyValue)
                    Case "y"
                        Window_Controls(tempLoop).Y = ValInt(PropertyValue)
                    Case "width"
                        Window_Controls(tempLoop).Width = ValInt(PropertyValue)
                    Case "height"
                        Window_Controls(tempLoop).Height = ValInt(PropertyValue)
                    Case "visible"
                        Window_Controls(tempLoop).Visible = ValInt(PropertyValue)
                    Case "enabled"
                        Window_Controls(tempLoop).Enabled = ValInt(PropertyValue)
                    Case "value"
                        Window_Controls(tempLoop).Value = ValInt(PropertyValue)
                    Case "text"
                        Window_Controls(tempLoop).Text_Length = Len(PropertyValue)
                        Window_Controls(tempLoop).Text = PropertyValue
                    Case "integer1"
                        Window_Controls(tempLoop).Integer1 = ValLng(PropertyValue)
                    Case "integer2"
                        Window_Controls(tempLoop).Integer2 = ValLng(PropertyValue)
                    Case "string1"
                        Window_Controls(tempLoop).String1_Length = Len(PropertyValue)
                        Window_Controls(tempLoop).String1 = PropertyValue
                    Case "string2"
                        Window_Controls(tempLoop).String2_Length = Len(PropertyValue)
                        Window_Controls(tempLoop).String2 = PropertyValue
                End Select
                Exit Do
            End If
        End If
    Loop

    #ifdef DEBUG_LOG
        LogString("SetControlProperty:End")
    #endif

    Return 0
End Function

' Creates a control
Function CreateControl(WindowNum As Integer, ProgramOwner As Integer, ControlName As String, ControlType As Integer) As Integer
    #ifdef DEBUG_LOG
        LogString("CreateControl")
    #endif

    ' Expand the array of controls
    TotalControls = TotalControls + 1
    ReDim Preserve Window_Controls(TotalControls)

    ' Assign the values now
    Window_Controls(TotalControls).ProgramOwner = ProgramOwner
    Window_Controls(TotalControls).Parent       = WindowNum
    Window_Controls(TotalControls).Name         = ControlName
    If Len(ControlName) > 64 Then
        Window_Controls(TotalControls).Name_Length = 64
    Else
        Window_Controls(TotalControls).Name_Length = Len(ControlName)
    End If
    
    Window_Controls(TotalControls).Type = ControlType

    ' If a Timer
    If ControlType = 0 Then
        CreateTimer(ProgramOwner, ControlName)
        'KernelPanic("Die!: " & ProgramOwner & " - " & ControlName)
    End If

    #ifdef DEBUG_LOG
        LogString("CreateControl:End")
    #endif

    Return 0
End Function

' Creates a usable window
Function CreateWindow(WindowName As String, WinWidth As Integer, WinHeight As Integer) As Integer
    #ifdef DEBUG_LOG
        LogString("CreateWindow")
    #endif

    WindowName = Trim(LCase(WindowName))

    TotalWindows = TotalWindows + 1

    ' Expand all the variables
    ReDim Preserve Window_Name(TotalWindows)
    ReDim Preserve Window_Image(TotalWindows)
    ReDim Preserve Window_ZOrder(TotalWindows)
    ReDim Preserve Window_Redraw(TotalWindows)
    ReDim Preserve Window_X1(TotalWindows)
    ReDim Preserve Window_Y1(TotalWindows)
    ReDim Preserve Window_X2(TotalWindows)
    ReDim Preserve Window_Y2(TotalWindows)
    ReDim Preserve Window_Visible(TotalWindows)
    ReDim Preserve Window_Caption(TotalWindows)
    ReDim Preserve Window_CaptionVisible(TotalWindows)
    ReDim Preserve Window_KBQueue(TotalWindows)

    Window_Name(TotalWindows) = WindowName
    Window_Image(TotalWindows) = ImageCreate(WinWidth, WinHeight, RGB(0, 0, 0))
    Window_ZOrder(TotalWindows) = TotalWindows
    Window_Visible(TotalWindows) = 1

    ' Move it to the top of the Z-Order list
    'SetZOrderTop (TotalWindows)

    ' Wasn't able to create the window!
    If Window_Image(TotalWindows) = 0 Then
        KernelPanic("Unable to create an image DC!")
    End If

    #ifdef DEBUG_LOG
        LogString("CreateWindow:End")
    #endif

    Return 0
End Function

Function CreateDoor(X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, WindowName As String, Caption As String) As Integer
    #ifdef DEBUG_LOG
        LogString("CreateDoor")
    #endif

    Dim As Integer tempInt
    Dim doorImage As Any Ptr
    tempInt = CreateWindow(WindowName, X2 - X1, Y2 - Y1)

    Window_X1(TotalWindows) = X1
    Window_Y1(TotalWindows) = Y1
    Window_X2(TotalWindows) = X2
    Window_Y2(TotalWindows) = Y2
    If Caption = "____NOTITLE____" Then
        Window_Caption(TotalWindows) = ""
        Window_CaptionVisible(TotalWindows) = 0
    Else
        Window_Caption(TotalWindows) = Caption
        Window_CaptionVisible(TotalWindows) = 1
    End If
      
    doorImage = GetWindowBuffer(WindowName)
      
    DrawDoor (doorImage, 0, 0, X2 - X1 - 1, Y2 - Y1 - 1, Caption, Window_CaptionVisible(TotalWindows))

    RedrawDoors()

    #ifdef DEBUG_LOG
        LogString("CreateDoor:End")
    #endif

    Return 0
End Function

Function GetWindowBufferTotalSize() As ULongInt
    #ifdef DEBUG_LOG
        LogString("GetWindowBufferTotalSize")
    #endif

    Dim As Integer tempLoop, success, imageSize
    Dim As ULongInt BufferTotal
    Do
        If (tempLoop > TotalWindows) Then
            GetWindowBufferTotalSize = BufferTotal
            Exit Do
        End If

        success = (ImageInfo(Window_Image(tempLoop),,,,,,imageSize) = 0)
        If success Then
            ' Image exists.  Use the size data
            BufferTotal = BufferTotal + imageSize
        End If

        tempLoop = tempLoop + 1
    Loop


    #ifdef DEBUG_LOG
        LogString("GetWindowBufferTotalSize:End")
    #endif
End Function

Function GetWindowBuffer(WindowName As String) As Any Ptr
    #ifdef DEBUG_LOG
        LogString("GetWindowBuffer")
    #endif

    Dim As Integer tempLoop

    WindowName = Trim(LCase(WindowName))
    Do
        If (tempLoop > TotalWindows) Then
            GetWindowBuffer = 0
            Exit Do
        End If

        If (LCase(Window_Name(tempLoop)) = WindowName) Then
            GetWindowBuffer = Window_Image(tempLoop)
            Exit Do
        End If
        tempLoop = tempLoop + 1
    Loop

    #ifdef DEBUG_LOG
        LogString("GetWindowBuffer:End")
    #endif
End Function

Function GetWindowNumber(WindowName As String) As Integer
    #ifdef DEBUG_LOG
        LogString("GetWindowNumber")
    #endif

    Dim As Integer tempLoop

    WindowName = Trim(LCase(WindowName))
    Do
        If (tempLoop > TotalWindows) Then
            GetWindowNumber = 0
            Exit Do
        End If

        If (LCase(Window_Name(tempLoop)) = WindowName) Then
            GetWindowNumber = tempLoop
            Exit Do
        End If
        tempLoop = tempLoop + 1
    Loop
    
    #ifdef DEBUG_LOG
    LogString("GetWindowNumber:End")
    #endif
End Function

' Routine to redraw all the doors based on the Z-Order
Sub RedrawDoors()
    #ifdef DEBUG_LOG
        LogString("RedrawDoors")
    #endif

    Dim As Integer tempLoop, returnVal, success

    tempLoop = TotalWindows

    ScreenLock()

    Do
        If (tempLoop < 1) Then
            Exit Do
        End If

        ' Only draw visible doors
        If Window_Visible(Window_ZOrder(tempLoop)) = 1 Then
            RedrawControls(tempLoop)
            success = (ImageInfo(Window_Image(Window_ZOrder(tempLoop)),,,,,,) = 0)
            If success Then
                ' Image exists.  Blit the door to the screen
                returnVal = BlitDoor(Window_ZOrder(tempLoop))
            End If
            Window_Redraw(Window_ZOrder(tempLoop)) = 0
        End If

        tempLoop = tempLoop - 1
    Loop

    ScreenUnlock()
    
    #ifdef DEBUG_LOG
        LogString("RedrawDoors:End")
    #endif
End Sub

' Routine to redraw the screen
Sub RedrawScreen()
    #ifdef DEBUG_LOG
        LogString("RedrawScreen")
    #endif

    Dim As Integer tempLoop

    ScreenLock()

    Dim desktopBackground As Any Ptr
    
    desktopBackground = GetWindowBuffer("Desktop")

    ' Line desktopBackground, (0, 0) - (1280, 1024), RGB(0, 128, 128), BF

    Put (0, 0), desktopBackground, PSet

    ' Set all the doors to redraw
    For tempLoop = 1 to TotalWindows
        Window_Redraw(tempLoop) = 1
    Next  ' tempLoop

    RedrawDoors()

    ' DrawTaskbar()

    ScreenUnLock()
    
    #ifdef DEBUG_LOG
        LogString("RedrawScreen:End")
    #endif
End Sub

Sub DrawTaskbar()
    #ifdef DEBUG_LOG
        LogString("DrawTaskbar")
    #endif

    Dim As Integer screen_width, screen_height
    Dim As Integer w, h
    Dim As String currentTime

    ' Get the 12-hour time
    currentTime = Left(Time(), 5)
    If CInt(Left(currentTime, 2)) > 12 Then
        currentTime = (CInt(Left(currentTime, 2)) - 12) & Mid(currentTime, 3) & "pm"
    Else
        currentTime = currentTime & "am"
    End If
      
    ' Get screen information
    ScreenInfo screen_width, screen_height

    ' Draw the taskbar itself
    Draw3DBox (0, 0, screen_height - 20, screen_width - 1, screen_height - 1, 0)

    ' Now the tray
    DrawButton (0, screen_width - 71, screen_height - 18, screen_width - 3, screen_height - 3, currentTime, 1)

    ' And the 'Use' button
    If UseMenuOpen = 0 Then
        DrawButton (0, 2, screen_height - 18, 38, screen_height - 3, "Use", 0)
    Else
        DrawButton (0, 2, screen_height - 18, 38, screen_height - 3, "Use", 1)
    End If
    
    ' Scrollbar Test Case
    'DrawScrollbar(0, 100, screen_height - 17, 200, screen_height - 3, 0, 100, RightClickCounter, 0, 0)
    'DrawText3D(0, 250, screen_height - 15, "" & RightClickCounter)
    
    #ifdef DEBUG_LOG
        LogString("DrawTaskbar:End")
    #endif
End Sub

Sub DisplayMultiLineSplitText(DC As Any Ptr, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, Caption As String, maxLines As Integer = 0, Split As String = " ", TextColor As ULong)
    #ifdef DEBUG_LOG
        LogString("DisplayMultiLineSplitText")
    #endif

    Dim totalMidPointX As Integer = (X2 - X1) / 2
    Dim totalMidPointY As Integer = (Y2 - Y1) / 2
    Dim As Integer tempMidPointX, tempMidPointY, totalLines, tempLocation
    Dim As String Lines(), tempLine

    If maxLines = 0 Then
        ' First, figure out the number of total lines (splitting on Split).
        ' As this is done, stuff the results of each line into the Lines() array.
        ReDim Preserve Lines(totalLines)
        Do
            Caption = LTrim(Caption)
            If Len(Caption) = 0 Then
                Exit Do
            End If
            If (Len(Caption) * 8) > (X2 - X1 - 6) Then
                tempLine = Left(Caption, ((X2 - X1 - 6) / 8))
                tempLocation = InStrRev(tempLine, Split)
                If (tempLocation > 0) Then
                    Lines(totalLines) = Trim(Left(tempLine, tempLocation))
                    Caption = Mid(Caption, tempLocation)
                    totalLines = totalLines + 1
                    ReDim Preserve Lines(totalLines)
                Else
                    Lines(totalLines) = Trim(tempLine)
                    Caption = Mid(Caption, ((X2 - X1 - 6) / 8) + 1)
                    totalLines = totalLines + 1
                    ReDim Preserve Lines(totalLines)
                End If
            Else
                Lines(totalLines) = Trim(Caption)
                Exit Do
            End If
        Loop

        totalMidPointY = totalMidPointY - ((totalLines - 1) * 4) - 3

        ' Now, render all the text
        For tempLocation = 0 To totalLines
            tempMidPointX = X1 + totalMidPointX - (Len(Lines(tempLocation)) * 4)
            tempMidPointY = Y1 + totalMidPointY - 4
            Draw String DC, (tempMidPointX, tempMidPointY), Lines(tempLocation), TextColor
            totalMidPointY = totalMidPointY + 8
        Next ' tempLocation
    ElseIf maxLines = 1 Then
        ' If the maximum length is greater than the width of the area,
        ' just cut off the caption so it fits.
        If (Len(Caption) * 8) > (X2 - X1 - 4) Then
            Caption = Left(Caption, ((X2 - X1 - 4) / 8))
        End If

        ' Calculate where to place the text
        tempMidPointX = X1 + totalMidPointX - (Len(Caption) * 4)
        tempMidPointY = Y1 + totalMidPointY - 4

        ' Place the text
        Draw String DC, (tempMidPointX, tempMidPointY), Caption, TextColor
    End If

    #ifdef DEBUG_LOG
        LogString("DisplayMultiLineSplitText:End")
    #endif
End Sub

' Draws a door
Sub DrawDoor(DC As Any Ptr, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, Caption As String, Visible As UByte)
    #ifdef DEBUG_LOG
        LogString("DrawDoor")
    #endif

    ' Draw the face
    Line DC, (X1 + 1, Y1 + 1) - (X2 - 1, Y2 - 1), ColorScheme.Door_Face, BF

    ' Draw the border
    Line DC, (X1, Y1) - (X2, Y2), ColorScheme.Door_Shadow, B
    Line DC, (X1, Y1) - (X2 - 1, Y1), ColorScheme.Door_HighLight
    Line DC, (X1, Y1) - (X1, Y2 - 1), ColorScheme.Door_HighLight

    If Visible = 1 Then
        ' Draw the titlebar
        Line DC, (X1 + 1, Y1 + 1) - (X2 - 1, Y1 + 12), ColorScheme.Door_CaptionBar, BF
        'DrawButton (X1 + 1, Y1 + 1, X2 - 12, Y1 + 12, Caption, 0, 1)

        ' Add the caption
        DisplayMultiLineSplitText(DC, X1 + 1, Y1 + 1, X2 - 12, Y1 + 12, Caption, 1, , ColorScheme.Door_CaptionText)
        'DisplayMultiLineSplitText(X1 + 1, Y1 + 1, X2 - 12, Y1 + 12, Caption, 1, RGB(255, 255, 255))
        DrawButton (DC, X2 - 12, Y1 + 1, X2 - 1, Y1 + 11, "X", 0, 0, 1)
    Else
        ' Fill everything in as the caption bar color
        Line DC, (X1 + 1, Y1 + 1) - (X2 - 1, Y2 - 1), ColorScheme.Door_CaptionBar, BF
    End If

    #ifdef DEBUG_LOG
        LogString("DrawDoor:End")
    #endif
End Sub

' Draws a 3d scrollbar.
Sub DrawScrollbar(DC As Any Ptr, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, Min As Long, Max As Long, Value As Long, State As Integer, Enabled As UByte = 1)
    #ifdef DEBUG_LOG
        LogString("DrawScrollbar")
    #endif

    Dim As Long Size        ' Size of Width/Height
    Dim As Single StepSize  ' Size of each step of the scrollbar
    Dim As Integer Location ' Location where the scrollwheel should start

    If State = 0 Then   ' Vertical Scrollbar
        If Enabled = 1 Then ' Enabled
            ' First, draw the actual bar
            Draw3DBox(DC, X1, Y1, X2, Y1 + 12, 1)

            ' Next, draw the left and right buttons
            DrawButton(DC, X1 + 1, Y1 + 1, X1 + 12, Y1 + 11, "<", 0, 1, 1)
            DrawButton(DC, X2 - 12, Y1 + 1, X2 -1 , Y1 + 11, ">", 0, 1, 1)

            ' Finally, the position indicator (Width - the width of the left and right arrows
            Size = X2 - X1 - 33
            StepSize = (Size / 100)
            'KernelPanic("Step: " & StepSize)
            Location = X1 + 12 + (((Value / Max) * 100) * StepSize)

            ' Make sure the locations are valid
            If Location < (X1 + 13) Then Location = X1 + 13
            If Location > (X2 - 25) Then Location = X2 - 25

            DrawButton(DC, Location, Y1 + 1, Location + 12, Y1 + 11, "|", 0, 1, 1)
        Else                ' Disabled        
            ' First, draw the actual bar
            Draw3DBox(DC, X1, Y1, X2, Y1 + 12, 1)

            ' Next, draw the left and right buttons
            DrawButton(DC, X1 + 1, Y1 + 1, X1 + 12, Y1 + 11, "<", 0, 0, 1)
            DrawButton(DC, X2 - 12, Y1 + 1, X2 -1 , Y1 + 11, ">", 0, 0, 1)

            ' Finally, the position indicator (Width - the width of the left and right arrows
            Size = X2 - X1 - 33
            StepSize = (Size / 100)
            'KernelPanic("Step: " & StepSize)
            Location = X1 + 12 + (((Value / Max) * 100) * StepSize)

            ' Make sure the locations are valid
            If Location < (X1 + 13) Then Location = X1 + 13
            If Location > (X2 - 25) Then Location = X2 - 25

            DrawButton(DC, Location, Y1 + 1, Location + 12, Y1 + 11, "|", 0, 0, 1)
        End If
    Else                ' Horizontal Scrollbar
    End If

    #ifdef DEBUG_LOG
        LogString("DrawScrollbar:End")
    #endif
End Sub

' Draws a 3d checkbox.  Will set it checked if State = 1.
Sub DrawCheckbox(DC As Any Ptr, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, Caption As String, State As UByte, Enabled As UByte = 1)
    #ifdef DEBUG_LOG
        LogString("DrawCheckbox")
    #endif

    ' Draw the box
    Draw3DBox (DC, X1, Y1, X1 + 10, Y1 + 10, 1)

    ' If it's enabled, set the background to white
    If Enabled = 1 Then
        Line DC, (X1 + 2, Y1 + 2) - (X1 + 8, Y1 + 8), ColorScheme.Button_HighlightOut, BF
    End If

    ' Check the box if State = 1 (Checked)
    If State = 1 Then
        Draw String DC, (X1 + 2, Y1 + 1), "x", ColorScheme.Door_Text
    End If

    If Enabled = 0 Then
        DisplayMultiLineSplitText(DC, X1 + 1, Y1 + 1, X2 + 1, Y1 + 11, " " & Caption, 1, , ColorScheme.Button_TextDisabledShadow)
        DisplayMultiLineSplitText(DC, X1, Y1, X2, Y1 + 10, " " & Caption, 1, , ColorScheme.Button_TextDisabled)
    Else
        DisplayMultiLineSplitText(DC, X1, Y1, X2, Y1 + 10 , " " & Caption, 1, , ColorScheme.Door_Text)
    End If

    'Line DC, (X1, Y1) - (X2, Y2), 0, B

    #ifdef DEBUG_LOG
        LogString("DrawCheckbox:End")
    #endif
End Sub

' Draws a 3D button.  Will set it inverted if State = 1
Sub DrawButton(DC As Any Ptr, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, Caption As String, State As UByte, Enabled As UByte = 1, MaxLines As UByte = 0)
    #ifdef DEBUG_LOG
        LogString("DrawButton")
    #endif

    Draw3DBox (DC, X1, Y1, X2, Y2, State)

    If Enabled = 0 Then
        DisplayMultiLineSplitText(DC, X1 + 1, Y1 + 1, X2 + 1, Y2 + 1, Caption, MaxLines, , ColorScheme.Button_TextDisabledShadow)
        DisplayMultiLineSplitText(DC, X1, Y1, X2, Y2, Caption, MaxLines, , ColorScheme.Button_TextDisabled)
    Else
        DisplayMultiLineSplitText(DC, X1, Y1, X2, Y2, Caption, MaxLines, , ColorScheme.Button_Text)
    End If

    #ifdef DEBUG_LOG
        LogString("DrawButton:End")
    #endif
End Sub

Sub Draw3DBox(DC As Any Ptr, X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer, Inverted As UByte)
    #ifdef DEBUG_LOG
        LogString("Draw3DBox")
    #endif

    Dim As ULong FaceColor, InsideShadow, InsideHighlight, OutsideShadow, OutsideHighLight
    
    FaceColor = RGB(198, 198, 198)
    
    If Inverted = 0 Then
        InsideHighLight = RGB(222, 222, 222)
        InsideShadow = RGB(132, 132, 132)
        OutsideShadow = RGB(0, 0, 0)
        OutsideHighLight = RGB(255, 255, 255)
    Else
        InsideShadow = RGB(222, 222, 222)
        InsideHighLight = RGB(132, 132, 132)
        OutsideHighLight = RGB(0, 0, 0)
        OutsideShadow = RGB(255, 255, 255)
    End If

    ' Draw the face
    Line DC, (X1 + 2, Y1 + 2) - (X2 - 2, Y2 - 2), ColorScheme.Button_Face, BF

    ' Draw the inside box
    Line DC, (X1 + 1, Y1 + 1) - (X2 - 1, Y2 - 1), ColorScheme.Button_ShadowIn, B
    Line DC, (X1 + 1, Y1 + 1) - (X2 - 2, Y1 + 1), ColorScheme.Button_HighlightIn
    Line DC, (X1 + 1, Y1 + 1) - (X1 + 1, Y2 - 2), ColorScheme.Button_HighlightIn

    ' Draw the outside box
    Line DC, (X1, Y1) - (X2, Y2), ColorScheme.Button_ShadowOut, B
    Line DC, (X1, Y1) - (X2 - 1, Y1), ColorScheme.Button_HighlightOut
    Line DC, (X1, Y1) - (X1, Y2 - 1), ColorScheme.Button_HighlightOut

    #ifdef DEBUG_LOG
        LogString("Draw3DBox:End")
    #endif
End Sub

' Routine to draw text with a shadow
Public Sub DrawText3D(DC As Any Ptr, X As Integer, Y As Integer, Text As String)
    #ifdef DEBUG_LOG
        LogString("DrawText3D")
    #endif

    Draw String DC, (X + 1, Y + 1), Text, RGB(0, 0, 0)
    Draw String DC, (X, Y), Text, RGB(255, 255, 255)

    #ifdef DEBUG_LOG
        LogString("DrawText3D:End")
    #endif
End Sub

' Routine to switch the screen resolution to the supplied one.  If it doesn't
' successfully switch, it will attempt 800x600x16bpp.  If that fails, the
' program will end.
Sub SwitchResolution(ScreenWidth As Integer, ScreenHeight As Integer, ScreenBitsPerPixel As Integer)
    #ifdef DEBUG_LOG
        LogString("SwitchResolution")
    #endif

    Dim As Integer w, h, bpp, pitch, ReturnCode

    ' Attempt to change the resolution
    ScreenRes ScreenWidth, ScreenHeight, ScreenBitsPerPixel, 2, GFX_FULLSCREEN

    ScreenInfo w, h, bpp

    Dim buffer As Any Ptr = ScreenPtr()
    
    If (buffer = 0) Then    ' Failed to switch, try a lower-grade resolution
        ScreenRes 800, 600, 16, 2
        buffer = ScreenPtr()
        If (buffer = 0) Then
            'KernelPanic "Unable to switch to a usable screen resolution!"
            KernelPanicQR 1
        End If
    End If

    ScreenInfo w, h, bpp
    ReturnCode = SetVariable("System.OS.Display.Width", Str(w))
    ReturnCode = SetVariable("System.OS.Display.Height", Str(h))
    ReturnCode = SetVariable("System.OS.Display.BitsPerPixel", Str(bpp))
    
    ' Since the resolution changed, force the whole screen to be updated
    UpdateScreen = 1

    #ifdef DEBUG_LOG
        LogString("SwitchResolution:End")
    #endif
End Sub

' Routine to assign the system colors to variables
Sub AssignColorsToVariables()
    AddVariable("System.OS.Colors.Door.Face", "integer", Str(ColorScheme.Door_Face))
    AddVariable("System.OS.Colors.Door.Text", "integer", Str(ColorScheme.Door_Text))
    AddVariable("System.OS.Colors.Door.Highlight", "integer", Str(ColorScheme.Door_Highlight))
    AddVariable("System.OS.Colors.Door.Shadow", "integer", Str(ColorScheme.Door_Shadow))
    AddVariable("System.OS.Colors.Door.Caption.Bar", "integer", Str(ColorScheme.Door_CaptionBar))
    AddVariable("System.OS.Colors.Door.Caption.Text", "integer", Str(ColorScheme.Door_CaptionText))
    AddVariable("System.OS.Colors.Button.Face", "integer", Str(ColorScheme.Button_Face))
    AddVariable("System.OS.Colors.Button.HighlightInside", "integer", Str(ColorScheme.Button_HighlightIn))
    AddVariable("System.OS.Colors.Button.ShadowInside", "integer", Str(ColorScheme.Button_ShadowIn))
    AddVariable("System.OS.Colors.Button.HighlightOutside", "integer", Str(ColorScheme.Button_HighlightOut))
    AddVariable("System.OS.Colors.Button.ShadowOutside", "integer", Str(ColorScheme.Button_ShadowOut))
    AddVariable("System.OS.Colors.Button.Text", "integer", Str(ColorScheme.Button_Text))
    AddVariable("System.OS.Colors.Button.TextDisabled", "integer", Str(ColorScheme.Button_TextDisabled))
    AddVariable("System.OS.Colors.Button.TextDisabledShadow", "integer", Str(ColorScheme.Button_TextDisabledShadow))
End Sub